//Our includes
#include "Vec3.h"

//Std includes
#include <math.h>

//! Initilizes the point with x = 0.0 y = 0.0 z = 0.0
Vec3::Vec3() {
    x = 0.0;
    y = 0.0;
    z = 0.0;
}

/*!
  \brief initilizes the point with init
  \param init - The value that x, y, z will be set to
  */
Vec3::Vec3(double init) {
    x = init;
    y = init;
    z = init;
}

/*!
  \brief initilizes the point
  \param x - The x component of the point
  \param y - The y component of the point
  \param z - The z component of the point
  */
Vec3::Vec3(double xValue, double yValue, double zValue) {
    x = xValue;
    y = yValue;
    z = zValue;
}

/*!
  \brief Copies the x, y, z from vec into this object
  \param vec - The vec3 that will be copied
  */
Vec3::Vec3(const Vec3& vec ) {
    Copy(vec);
}

/*!
  \brief the assigment operator
  Copyies x,y,z from vec to this object
  \param vec - The value that will be copied
*/
Vec3 Vec3::operator=(const Vec3& vec)  {
    Copy(vec);
   return *this;
}

/*!
  \brief Muliplies each component by value.
  \param value - The x, y, z are all multipled by this value

  Example:
  \code
  Vec3 point1(2.0, 3.0, 4.0);
  Vec3 point2 = point * 4.0; //point2 = 8.0, 12.0, 16.0
  \endcode
*/
Vec3 Vec3::operator*(double value) const {

    double newX = x * value;
    double newY = y * value;
    double newZ = z * value;

    return Vec3(newX, newY, newZ);
}

/*!
  \brief Multiplies component wise
  \param vec - The vec3 that we want to multiple by

  Example:
  \code
  Vec3 point1(2.0, 3.0, 4.0);
  Vec3 point2(5.0, 6.0, 7.0);
  Vec3 point3 = point1 * point2;

  //Point point3 = 10.0, 18.0, 28.0
  */
Vec3 Vec3::operator*(const Vec3& vec) const {
    double newX = x * vec.x;
    double newY = y * vec.y;
    double newZ = z * vec.z;

    return Vec3(newX, newY, newZ);
}

/*!
  \brief Divides each component by value
  \param value - the denominator, shouldn't be zero, isn't checked

  Example:
  \code
  Vec3 point1(2.0, 4.0, 6.0);
  vec3 point2 = point1 / 2.0;
  //point2 = 1.0, 2.0, 3.0
  \endcode
  */
Vec3 Vec3::operator/(double value) const {
    double newX = x / value;
    double newY = y / value;
    double newZ = z / value;

    return Vec3(newX, newY, newZ);
}

/*!
  \brief Divides component wise
  \param vec - the denominator

  Example:
  \code
    Vec3 point1(2.0, 9.0, 16.0);
    Vec3 point2(2.0, 3.0, 4.0);
    Vec3 point3 = point1 / point2;
    //point3 = 1.0, 3.0, 4.0
  \endcode
  */
Vec3 Vec3::operator/(const Vec3& vec) const {
    double newX = x / vec.x;
    double newY = y / vec.y;
    double newZ = z / vec.z;

    return Vec3(newX, newY, newZ);
}

/*!
  \brief Adds to the vectors together
  \param vec - The vector that will be added to this object

  Example:
  \code
  Vec3 point1(1.0, 2.0, 3.0);
  Vec3 point2(4.0, 5.0, 6.0);
  Vec3 point3 = point1 + point2;
  //point3 = 5.0, 7.0, 9.0
  \endcode
*/
Vec3 Vec3::operator+(const Vec3& vec) const {
    double newX = x + vec.x;
    double newY = y + vec.y;
    double newZ = z + vec.z;
    return Vec3(newX, newY, newZ);
}

/*!
  \brief Finds the diffance between two vectors
  \param vec - The vector that will be subtracted with this object

  Example:
  \code
  Vec3 point1(1.0, 2.0, 3.0)
  Vec3 point2(6.0, 5.0, 4.0)
  Vec3 point3 = point2 - point1;
  //  point2.x - point1.x ... etc.
  //point3 = 5.0, 3.0, 1.0
  \endcode
  */
Vec3 Vec3::operator-(const Vec3& vec) const {
    double newX = x - vec.x;
    double newY = y - vec.y;
    double newZ = z - vec.z;
    return Vec3(newX, newY, newZ);
}

/*!
  \brief Gets the length of the vector
  sqrt(x*x + y*y + z*z);

  \return The length of the vector
  */
double Vec3::Length() const {
    return sqrt(x*x + y*y + z*z);
}

/*!
  \brief Returns a unit vector of the vector

  A unit vector is where the length of the vector is
  equal to one.
  */
Vec3 Vec3::Normalize() const {
    double length = Length();
    double normX = x / length;
    double normY = y / length;
    double normZ = z / length;
    return Vec3(normX, normY, normZ);
}

//Copy helper function to the assignment and copy constructor
void Vec3::Copy(const Vec3 vec) {
    x = vec.x;
    y = vec.y;
    z = vec.z;
}
